package com.cxyd.modules.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxyd.common.Utils.BeanUtils;
import com.cxyd.common.constant.enums.wms.TaskStEnum;
import com.cxyd.common.exception.RootException;
import com.cxyd.common.page.PageData;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ProcResult;
import com.cxyd.modules.api.dto.request.TaskRequest;
import com.cxyd.modules.security.user.SecurityUser;
import com.cxyd.modules.sys.dto.SysUserDTO;
import com.cxyd.modules.sys.service.SysUserService;
import com.cxyd.modules.wms.dao.*;
import com.cxyd.modules.wms.dto.TaskDTO;
import com.cxyd.modules.wms.entity.*;
import com.cxyd.modules.wms.service.ContainerDetailService;
import com.cxyd.modules.wms.service.PostWcsService;
import com.cxyd.modules.wms.service.StockService;
import com.cxyd.modules.wms.service.TaskService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 业务记录
 *
 * @author g_Cycle gengruyi01@163.com
 * @since 1.0.0 2023-04-27
 */
@Service
public class TaskServiceImpl extends CrudServiceImpl<TaskDao, TaskEntity, TaskDTO> implements TaskService {
    @Resource
    private SysUserService userService;
    @Resource
    private LocateDao locateDao;
    @Resource
    private ContainerDao containerDao;
    @Resource
    private ContainerDetailDao containerDetailDao;
    @Resource
    private ContainerDetailService containerDetailService;
    @Resource
    private PostWcsService postWcsService;
    @Resource
    private TaskDao taskDao;
    @Resource
    private SpuDao spuDao;
    @Resource
    private TaskBakDao taskBakDao;
    @Resource
    private StockDao stockDao;

    @Override
    public PageData<TaskDTO> page(Map<String, Object> params) {
        //1.获取任务信息
        IPage<TaskEntity> page = baseDao.selectPage(
                getPage(params, "task_id", false),
                getWrapper(params)
        );
        //2.获取用户列表
        List<SysUserDTO> userList = userService.getList();
        //3.将creator与updater的username通过id进行绑定
        page.getRecords().forEach(entity -> {
            if (entity.getCreator() != null) {
                entity.setCreatorName(userService.getUsernameById(entity.getCreator(), userList));
            }
            if (entity.getUpdater() != null) {
                entity.setUpdaterName(userService.getUsernameById(entity.getUpdater(), userList));
            }
        });
        return getPageData(page, TaskDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long[] ids) {
//        任务取消
        for (Long id : ids) {
            taskCancelById(id);
        }
    }

    public void taskCancelById(Long taskId) {
//        根据ID获取任务
        TaskEntity taskEntity = baseDao.selectById(taskId);
        if (taskEntity == null) {
            throw new RootException("任务[" + taskId + "]不存在!无法取消");
        }
//        只有入库任务可以取消
        if ("02".equals(taskEntity.getTaskType())) {
            throw new RootException("任务[" + taskId + "]为出库任务!无法取消");
        }
//        任务状态初始或执行中允许取消
        if (taskEntity.getTaskSt() > 1) {
            throw new RootException("任务[" + taskId + "]当前状态为[" + taskEntity.getTaskSt() + "]不允许取消");
        }
//        删除任务对应的库存信息
        stockDao.deleteById(taskEntity.getStockId());
//        将任务状态更新为取消
        taskEntity.setTaskSt(9);
        taskEntity.setUpdateDate(new Date());
        taskEntity.setUpdater(SecurityUser.getUser().getId());
        baseDao.updateById(taskEntity);
    }

    @Override
    public QueryWrapper<TaskEntity> getWrapper(Map<String, Object> params) {
        String taskId = (String) params.get("taskId");
        String taskType = (String) params.get("taskType");
        String taskSubType = (String) params.get("taskSubType");
        String contNo = (String) params.get("contNo");
        String spuNo = (String) params.get("spuNo");
        String spuName = (String) params.get("spuName");
        String curPosition = (String) params.get("curPosition");

        String mtNo = (String) params.get("mtNo");
        String detailId = (String) params.get("detailId");
        String taskSt = (String) params.get("taskSt");


        QueryWrapper<TaskEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(taskId), "task_id", taskId);
        wrapper.eq(StringUtils.isNotBlank(taskType), "task_type", taskType);
        wrapper.eq(StringUtils.isNotBlank(taskSubType), "task_sub_type", taskSubType);
        wrapper.eq(StringUtils.isNotBlank(mtNo), "mt_no", mtNo);
        wrapper.eq(StringUtils.isNotBlank(detailId), "detail_id", detailId);
        if (StringUtils.isBlank(taskSt)) {
            wrapper.lt("task_st", 9);
        } else {
            wrapper.eq("task_st", taskSt);
        }
        wrapper.like(StringUtils.isNotBlank(contNo), "cont_no", contNo);
        wrapper.like(StringUtils.isNotBlank(curPosition), "current_position", curPosition);
        wrapper.like(StringUtils.isNotBlank(spuNo), "spu_no", spuNo);
        wrapper.like(StringUtils.isNotBlank(spuName), "spu_name", spuName);

        return wrapper;
    }

    @Override
    public PageData<TaskDTO> rfPage(Map<String, Object> params) {
        String contNo = (String) params.get("contNo");
        if (StringUtils.isBlank(contNo)) {
            return null;
        }
        String taskType = (String) params.get("taskType");
        String taskSubType = (String) params.get("taskSubType");
        QueryWrapper<TaskEntity> rfWrapper = new QueryWrapper<>();
        rfWrapper.eq("cont_no", contNo);
        rfWrapper.eq(StringUtils.isNotBlank(taskType), "task_type", taskType);
        rfWrapper.eq(StringUtils.isNotBlank(taskSubType), "task_sub_type", taskSubType);
        rfWrapper.lt("task_st", 2);
        IPage<TaskEntity> page = baseDao.selectPage(getPage(params, "task_id", true),
                rfWrapper
        );
        return getPageData(page, TaskDTO.class);
    }

    @Override
    public ProcResult taskAffirm(Map<String, Object> params) {
        //对主要参数进行校验
        String taskId = (String) params.get("taskId");
        if (StringUtils.isBlank(taskId)) {
            return new ProcResult().result("123", "任务号不能为空!");
        }
        baseDao.procTaskAffirm(params);
        String code = (String) params.get("code");
        String msg = (String) params.get("msg");
        return new ProcResult().result(code, msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcResult requestContOut(Map<String, Object> params) {
        ProcResult result = new ProcResult();
        try {
            //托盘请求出库
            //输入REELID
            //获取REELID对应物料+规格
            //出库响应规格的料箱
            String reelId = (String) params.get("reelId");//给reelid复制
            String spuNo = "123";//物料编码
            String spuType = "16";//物料规格来确定料箱规格
            String contType = "16格";//容器规格
            String toLocate = locateDao.selectOne(new QueryWrapper<LocateEntity>()
                    .eq("locate_type", "ST")).getLocateNo();//操作货位;//出库目标货位
            Long userId = SecurityUser.getUser().getId();
            Date now = new Date();

            //查找空料箱
            LocateEntity locateEntity = containerDao.getContOut(spuNo, contType, "");
            //下发出库任务 wms_task + wms_post_wcs
            TaskEntity taskEntity = new TaskEntity();

            taskEntity.setTaskType("02");
            taskEntity.setTaskSubType("021");
            taskEntity.setContNo(locateEntity.getContNo());
            taskEntity.setComments(reelId);
            taskEntity.setTaskSt(1);
            taskEntity.setSpuNo(spuNo);
            taskEntity.setFromPosition(locateEntity.getLocateNo());
            taskEntity.setCurrentPosition(locateEntity.getLocateNo());
            taskEntity.setToPosition(toLocate);
            taskEntity.setCreateDate(now);
            taskEntity.setUpdateDate(now);
            taskEntity.setCreator(userId);
            taskEntity.setUpdater(userId);

            if (insert(taskEntity)) {
                //wms_post_wcs下发设备任务

                PostWcsEntity postWcsEntity = new PostWcsEntity();
                postWcsEntity.setContNo(locateEntity.getContNo());
                postWcsEntity.setRequestPk(UUID.randomUUID().toString().replace("-", ""));
                postWcsEntity.setContType(contType);
                postWcsEntity.setFrmPos(locateEntity.getLocateNo());
                postWcsEntity.setCurPos(locateEntity.getLocateNo());
                postWcsEntity.setToPos(toLocate);
                postWcsEntity.setTrkType("OT");
                postWcsEntity.setTrkPrty("1");
                postWcsEntity.setCreateDate(now);
                postWcsEntity.setUpdateDate(now);
                postWcsEntity.setCreator(userId);
                postWcsEntity.setUpdater(userId);
                if (postWcsService.insert(postWcsEntity)) {
                    //返回成功
                    result.setCode("0");
                    result.setMsg("料箱请求成功" + locateEntity.getContNo());

                } else {
                    throw new Exception("任务生成失败");
                }

            }

        } catch (Exception ex) {
            //返回失败
            result.setCode("-1");
            result.setMsg(ex.getMessage());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcResult requestContIn(Map<String, Object> params) {
        //由于入库登记直接分配货位，所以所有入库登记都用这个方法
        ProcResult result = new ProcResult();
        String requestType = (String) params.get("requestType");//0-空托盘登记 1-入库登记 2-盘点回库
        try {
            if (requestType.equals("0")) {
                //空箱入库
                //输入托盘号+托盘类型
                //生成容器信息和容器明细货格
                //分配货位，生成入库任务
                String contNo = (String) params.get("contNo");//箱码
                String contType = (String) params.get("contType");//容器规格
                String toLocate = "";//入库目标货位
                String fromLocate = locateDao.selectOne(new QueryWrapper<LocateEntity>()
                        .eq("locate_type", "ST")).getLocateNo();//操作货位
                Long userId = SecurityUser.getUser().getId();
                Date now = new Date();

                int countLocate = 0;

                if (contType.equals("16格")) {
                    countLocate = 16;
                } else if (contType.equals("10格")) {
                    countLocate = 10;
                } else {
                    result.setCode("-1");
                    result.setMsg("箱类型不正确");
                    return result;
                }
                //查看此容器是否存在，存在就报错
                QueryWrapper<ContainerEntity> contWrapper = new QueryWrapper<ContainerEntity>()
                        .eq("cont_no", contNo);
                if (containerDao.exists(contWrapper)) {
                    throw new Exception("此箱码已登记，不能重复登记");
                }
                ContainerEntity contInsert = new ContainerEntity();
                contInsert.setContNo(contNo);
                contInsert.setContType(contType);
                contInsert.setContDescription(contType + "料箱");
                contInsert.setCreateDate(now);
                contInsert.setUpdateDate(now);
                contInsert.setCreator(userId);
                contInsert.setUpdater(userId);
                if (containerDao.insert(contInsert) >= 1) {
                    //查看此容器货格是否存在，存在就报错
                    QueryWrapper<ContainerDetailEntity> contDtWrapper = new QueryWrapper<ContainerDetailEntity>()
                            .eq("cont_no", contNo);
                    if (containerDetailDao.exists(contDtWrapper)) {
                        //没有主表信息有明细信息？这个情况不正常

                        //result.setMsg("此箱码已有货格信息，不能重复登记");
                        throw new Exception("此箱码已有货格信息，不能重复登记");
                    }

                    //批量插入  16或10个货格信息
                    List<ContainerDetailEntity> contDtList = new ArrayList<>();

                    for (int i = 1; i <= countLocate; i++) {
                        ContainerDetailEntity contDtInsert = new ContainerDetailEntity();
                        contDtInsert.setContNo(contNo);
                        contDtInsert.setContLocateNo(contNo + "-" + i);
                        contDtInsert.setCreateDate(now);
                        contDtInsert.setUpdateDate(now);
                        contDtInsert.setCreator(userId);
                        contDtInsert.setUpdater(userId);
                        contDtList.add(contDtInsert);
                    }
                    if (containerDetailService.insertBatch(contDtList)) {
                        //插入成功，分配货位，生成任务
                        QueryWrapper<LocateEntity> locateWrapper = new QueryWrapper<LocateEntity>()
                                .eq("locate_type", "HW")
                                .eq("locate_st", 0);
                        LocateEntity toLocateEntity = new LocateEntity();
                        toLocateEntity = locateDao.selectList(locateWrapper).get(0);
                        toLocate = toLocateEntity.getLocateNo();
                        //货位状态  更新为已分配
                        toLocateEntity.setLocateSt(1);
                        locateDao.updateById(toLocateEntity);

                        //下发出库任务 wms_task + wms_post_wcs
                        TaskEntity taskEntity = new TaskEntity();

                        taskEntity.setTaskType("01");
                        taskEntity.setTaskSubType("011");
                        taskEntity.setContNo(contNo);
                        taskEntity.setComments("空箱登记");
                        taskEntity.setTaskSt(1);
                        taskEntity.setFromPosition(fromLocate);
                        taskEntity.setCurrentPosition(fromLocate);
                        taskEntity.setToPosition(toLocate);
                        taskEntity.setCreateDate(now);
                        taskEntity.setUpdateDate(now);
                        taskEntity.setCreator(userId);
                        taskEntity.setUpdater(userId);

                        if (insert(taskEntity)) {
                            //wms_post_wcs下发设备任务

                            PostWcsEntity postWcsEntity = new PostWcsEntity();
                            postWcsEntity.setContNo(contNo);
                            postWcsEntity.setRequestPk(UUID.randomUUID().toString().replace("-", ""));
                            postWcsEntity.setContType(contType);
                            postWcsEntity.setFrmPos(fromLocate);
                            postWcsEntity.setCurPos(fromLocate);
                            postWcsEntity.setToPos(toLocate);
                            postWcsEntity.setTrkType("IN");
                            postWcsEntity.setTrkPrty("1");
                            postWcsEntity.setCreateDate(now);
                            postWcsEntity.setUpdateDate(now);
                            postWcsEntity.setCreator(userId);
                            postWcsEntity.setUpdater(userId);
                            if (postWcsService.insert(postWcsEntity)) {
                                //返回成功
                                result.setCode("0");
                                result.setMsg("料箱" + contNo + "成功登记入库");

                            } else {
                                //返回失败
                                //result.setMsg("任务生成失败");
                                throw new Exception("任务生成失败");
                            }
                        }
                    }
                }

            } else if (requestType.equals("1")) {
                //reelid 登记入库
                //输入参数 reelid，料箱号，物料号，批号，数量，datacode，货格号
            }

        } catch (Exception ex) {
            result.setCode("-1");
            result.setMsg(ex.getMessage());
        }
        return result;
    }

    /**
     * 生成任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void taskInsert(TaskEntity taskEntity) {
        //任务是否存在
        String contNo = taskEntity.getContNo();
        List<TaskEntity> taskEntityList = taskDao.selectList(new QueryWrapper<TaskEntity>()
                .eq("cont_no", contNo)
                .ne("task_sub_type", taskEntity.getTaskSubType())
                .lt("task_st", TaskStEnum.COMPLETE.getCode()));
        if (null != taskEntityList && taskEntityList.size() > 0) {
            TaskEntity top1Task = taskEntityList.get(0);
            String msg = "托盘[" + contNo + "]已存在其他场景的业务!ID[" + top1Task.getTaskId() + "]";
            throw new RootException(msg);
        }

        //查物料
        if (StringUtils.isBlank(taskEntity.getSpuName())) {
            List<SpuEntity> spuEntities = spuDao.selectList(new QueryWrapper<SpuEntity>().eq("spu_no", taskEntity.getSpuNo()));
            String spuName;
            if (CollectionUtils.isEmpty(spuEntities)) {
                spuName = "未知物料";
            } else {
                spuName = spuEntities.get(0).getSpuName();
            }
            taskEntity.setSpuName(spuName);
        }

        taskDao.insert(taskEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void backUp(Date date, Integer num) {
        while (true) {
            List<TaskEntity> taskEntityList = taskDao.selectForBackup(date, num);
            if (CollectionUtils.isEmpty(taskEntityList)) {
                return;
            }
            List<TaskBakEntity> list = new ArrayList<>();
            for (TaskEntity task : taskEntityList) {
                TaskBakEntity taskBak = new TaskBakEntity();
                BeanUtils.copyProperties(task, taskBak);
                list.add(taskBak);
            }
            taskBakDao.batchInsert(list);
            List<Long> ids = taskEntityList.stream().map(TaskEntity::getTaskId).collect(Collectors.toList());
            taskDao.deleteBatchIds(ids);
        }
    }

    @Override
    public List<TaskEntity> taskQuery(String contNo, String taskSubType) {
        return taskDao.selectList(new QueryWrapper<TaskEntity>().eq("cont_no", contNo).eq("task_st", TaskStEnum.PROGRESS.getCode()).eq("task_sub_type", taskSubType));
    }

    @Override
    public void updateQty(TaskDTO dto) {
        this.update(dto);

        //修改任务的物料数量时，也须将库存一并修改
        QueryWrapper<StockEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(StockEntity:: getContNo,dto.getContNo())
                .eq(StockEntity:: getSpuNo,dto.getSpuNo());
        StockEntity stockEntity = stockDao.selectOne(qw);
        stockEntity.setStockQty(dto.getActlQty());
        stockDao.updateById(stockEntity);
    }


}